package org.example.dbcompare.service.data;

import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.db.ds.simple.SimpleDataSource;
import lombok.extern.slf4j.Slf4j;
import org.example.dbcompare.model.result.CompareDataItem;
import org.example.dbcompare.model.config.DataCompareItem;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
public class AddCompare extends CompareBase{

    public AddCompare(SimpleDataSource sourceDataSource, SimpleDataSource targetDataSource) {
        super(sourceDataSource, targetDataSource);
    }
    @Override

    public void compare(
                               DataCompareItem cfgItem,
                               CompareDataItem  item){
        String table = cfgItem.getTableName();
        List<String> keyColumns = resolveKeyColumns(sourceDataSource, table, cfgItem);
        if (keyColumns == null || keyColumns.isEmpty()) {
            log.warn("表 {} 未能解析到主键/对比键，跳过插入差异计算", table);
            return;
        }
        String where = cfgItem.getWhereClause();
        String columnList = String.join(", ", keyColumns);
        String baseSql = "SELECT " + columnList + " FROM " + table + (where != null && !where.isEmpty() ? " WHERE " + where : "");
        List<Entity> srcEntities;
        List<Entity> tgtEntities;
        try {
            srcEntities = Db.use(sourceDataSource).query(baseSql);
            tgtEntities = Db.use(targetDataSource).query(baseSql);
        } catch (Exception e) {
            log.error("查询主键集合失败, 表 {}: {}", table, e.getMessage(), e);
            return;
        }

        Set<String> tgtKeySet = new HashSet<>();
        for (Entity e : tgtEntities) {
            tgtKeySet.add(buildKeyValue(e, keyColumns));
        }

        List<Map<String,Object>> missingRows = new ArrayList<>();
        for (Entity e : srcEntities) {
            String k = buildKeyValue(e, keyColumns);
            if (!tgtKeySet.contains(k)) {
                Map<String,Object> rowKey = new HashMap<>();
                for (String col : keyColumns) {
                    rowKey.put(col, e.get(col));
                }
                missingRows.add(rowKey);
            }
        }
        if (!missingRows.isEmpty()) {
            item.setMismatchRows(missingRows);
            item.setMismatchRowCount(missingRows.size());
            item.setEqual(false);
        }
    }

    /**
     * 解析对比键：优先使用配置compareKeys，其次表主键；若均无则退化为所有列
     */
    private List<String> resolveKeyColumns(SimpleDataSource dataSource, String table, DataCompareItem cfgItem) {
        if (cfgItem.getCompareKeys() != null && !cfgItem.getCompareKeys().isEmpty()) {
            return cfgItem.getCompareKeys();
        }
        try (Connection conn = dataSource.getConnection()) {
            DatabaseMetaData meta = conn.getMetaData();
            String catalog = conn.getCatalog();
            String schema = conn.getSchema();
            List<String> pkCols = new ArrayList<>();
            ResultSet rsPk = null;
            try {
                rsPk = meta.getPrimaryKeys(catalog, schema, table);
                while (rsPk.next()) {
                    String col = rsPk.getString("COLUMN_NAME");
                    if (col != null && !col.isEmpty()) {
                        pkCols.add(col);
                    }
                }
            } catch (Exception ignore) {
                log.warn("读取表 {} 主键失败: {}", table, ignore.getMessage());
            } finally {
                if (rsPk != null) {
                    try { rsPk.close(); } catch (Exception e) { /* ignore */ }
                }
            }
            if (!pkCols.isEmpty()) {
                return pkCols;
            }
            // 无主键则退化为所有列
            List<String> allCols = new ArrayList<>();
            ResultSet rsCols = null;
            try {
                rsCols = meta.getColumns(catalog, schema, table, null);
                while (rsCols.next()) {
                    String col = rsCols.getString("COLUMN_NAME");
                    if (col != null && !col.isEmpty()) {
                        allCols.add(col);
                    }
                }
            } catch (Exception ignore) {
                log.warn("读取表 {} 列信息失败: {}", table, ignore.getMessage());
            } finally {
                if (rsCols != null) {
                    try { rsCols.close(); } catch (Exception e) { /* ignore */ }
                }
            }
            return allCols;
        } catch (Exception e) {
            log.error("解析表 {} 主键信息失败: {}", table, e.getMessage(), e);
            return cfgItem.getCompareKeys();
        }
    }

    /**
     * 将一行主键列值构造为比较用字符串键
     */
    private String buildKeyValue(Entity entity, List<String> keyColumns) {
        return keyColumns.stream()
                .map(col -> {
                    Object v = entity.get(col);
                    return v == null ? "<NULL>" : String.valueOf(v);
                })
                .collect(Collectors.joining("\u0001"));
    }
}
